#pragma once

namespace mmath
{
	class Ray;
}

namespace mphys
{
	class PhysicsSystem;

	struct RigidBodyDesc
	{
		float Density;
		XMFLOAT3 Position;
		XMFLOAT4 Orientation;
		XMFLOAT3 Scale;
		bool IsStatic;
	};

	class RigidBody
	{
	public:
		float Mass;
		float MassInverse;

		XMFLOAT3X3 InertiaTensor;
		XMFLOAT3X3 InertiaTensorInverse;
		XMFLOAT3X3 WorldSpaceInertiaTensorInverse;

		XMFLOAT3 Position;
		XMFLOAT4 Orientation;
		XMFLOAT4X4 WorldMatrix;

		XMFLOAT3 Velocity;
		XMFLOAT3 RealVelocity;
		XMFLOAT3 AngularVelocity;

		XMFLOAT3 ForceAccum;
		XMFLOAT3 TorqueAccum;

		XMFLOAT3 Acceleration;

		XMFLOAT3 LastFrameVelocityChange; // Used by contact resolver for resting contacts. Set by rigid body, read by contact resolver.
		XMFLOAT3 ContactResolutionPositionChange; // Used by contact resolver. Both set and read by resolver.

		typedef uint ID;
		ID Id;

		PhysicsSystem * System;
		virtual RigidBody & copy() = 0;

		virtual void reset(const RigidBodyDesc & desc) = 0;

		void addForce(XMVECTOR force);
		void addForceAtPoint(XMVECTOR force, XMVECTOR point);

		void clearAccums();
		void updateWorldMatrix();
		void applyGravity(float dt);

		void update(float dt);
		void updatePosition(float dt);
		void updateOrientation(float dt);

		virtual float checkRayIntersection(const mmath::Ray & ray) = 0;

	protected:
		void initDynamic(const XMFLOAT3 & position, const XMFLOAT4 & orientation, float mass, const XMFLOAT3X3 & inertiaTensor);
		void initStatic(const XMFLOAT3 & position, const XMFLOAT4 & orientation); // for static geometry!
	};
}